package me.kuye.jkuye.render;

import java.io.File;
import java.util.Locale;

import javax.servlet.ServletContext;

import me.kuye.jkuye.config.Constants;
import me.kuye.jkuye.core.Const;
import me.kuye.jkuye.helper.PathHelper;
import me.kuye.jkuye.plugin.activerecord.ModelRecordElResolver;

public class RenderFactory {
	private static final RenderFactory renderFactory = new RenderFactory();
	private static ServletContext servletContext;
	private static IMainRenderFactory mainRenderFactory;
	private static IErrorRenderFactory errorRenderFactory;
	private Constants constants;

	private RenderFactory() {

	}

	public static RenderFactory getInstance() {
		return renderFactory;
	}

	public void init(ServletContext servletContext, Constants constants) {
		this.constants = constants;
		RenderFactory.servletContext = servletContext;

		Render.init(constants.getEncoding(), constants.getDevMode());
		initFreeMarkerRender(servletContext);
		initVelocityRender(servletContext);
		initJspRender(servletContext);
		initFileRender(servletContext);

		if (mainRenderFactory == null) {
			ViewType defaultViewType = constants.getViewType();
			if (defaultViewType == ViewType.FREE_MARKER)
				mainRenderFactory = new FreeMarkerRenderFactory();
			else if (defaultViewType == ViewType.JSP)
				mainRenderFactory = new JspRenderFactory();
			else if (defaultViewType == ViewType.VELOCITY)
				mainRenderFactory = new VelocityRenderFactory();
			else
				throw new RuntimeException("View Type can not be null.");
		}

		if (errorRenderFactory == null) {
			errorRenderFactory = new ErrorRenderFactory();
		}
	}

	private void initFileRender(ServletContext servletContext) {
		try {
			FileRender.init(getFileRenderPath(), servletContext);
		} catch (Exception e) {
		}
	}

	private void initJspRender(ServletContext servletContext) {
		try {
			Class.forName("javax.el.ELResolver");
			Class.forName("javax.servlet.jsp.JspFactory");
			ModelRecordElResolver.init(servletContext);
		} catch (Exception e) {
		}
	}

	//
	private void initVelocityRender(ServletContext servletContext) {
		try {
			Class.forName("org.apache.velocity.VelocityContext");
			VelocityRender.init(servletContext);
		} catch (Exception e) {
		}
	}

	private void initFreeMarkerRender(ServletContext servletContext) {
		try {
			Class.forName("freemarker.template.Templater");
			FreeMarkerRender.init(servletContext, Locale.getDefault(), constants.getFreemarkerTemplateUpdateDelay());
		} catch (Exception e) {
		}
	}

	public static void setMainRenderFactory(IMainRenderFactory mainRenderFactory) {
		if (mainRenderFactory != null)
			RenderFactory.mainRenderFactory = mainRenderFactory;
	}

	public static void setErrorRenderFactory(IErrorRenderFactory errorRenderFactory) {
		if (errorRenderFactory != null)
			RenderFactory.errorRenderFactory = errorRenderFactory;
	}

	static ServletContext getServletContext() {
		return servletContext;
	}

	private String getFileRenderPath() {
		String result = constants.getFileRenderPath();
		if (result == null) {
			result = PathHelper.getWebRootPath() + Const.DEFAULT_FILE_RENDER_BASE_PATH;
		}
		if (!result.endsWith(File.separator) && !result.endsWith("/")) {
			result = result + File.separator;
		}
		return result;
	}

	private static final class FreeMarkerRenderFactory implements IMainRenderFactory {
		public Render getRender(String view) {
			return new FreeMarkerRender(view);
		}

		public String getViewExtension() {
			return ".html";
		}
	}

	private static final class JspRenderFactory implements IMainRenderFactory {
		public Render getRender(String view) {
			return new JspRender(view);
		}

		public String getViewExtension() {
			return ".jsp";
		}
	}

	private static final class VelocityRenderFactory implements IMainRenderFactory {
		public Render getRender(String view) {
			return new VelocityRender(view);
		}

		public String getViewExtension() {
			return ".html";
		}
	}

	private static final class ErrorRenderFactory implements IErrorRenderFactory {
		public Render getRender(int errorCode, String view) {
			return new ErrorRender(errorCode, view);
		}
	}

	/**
	 * return the render by the default ViewPath
	 * 
	 */

	public Render getRender(String view) {
		return mainRenderFactory.getRender(view);
	}

	public Render getFreeMarkerRender(String view) {
		return new FreeMarkerRender(view);
	}

	public Render getJspRender(String view) {
		return new JspRender(view);
	}

	public Render getVelocityRender(String view) {
		return new VelocityRender(view);
	}

	public Render getDefaultRender(String view) {
		ViewType viewType = constants.getViewType();
		if (viewType == ViewType.FREE_MARKER) {
			return new FreeMarkerRender(view + constants.getFreeMarkerViewExtension());
		} else if (viewType == ViewType.JSP) {
			return new JspRender(view + constants.getJspViewExtension());
		} else if (viewType == ViewType.VELOCITY) {
			return new VelocityRender(view + constants.getVelocityViewExtension());
		} else {
			return mainRenderFactory.getRender(view + mainRenderFactory.getViewExtension());
		}
	}

	public Render getErrorRender(int errorCode, String view) {
		return errorRenderFactory.getRender(errorCode, view);
	}

	public Render getErrorRender(int errorCode) {
		return errorRenderFactory.getRender(errorCode, constants.getErrorView(errorCode));
	}

}
